import base64
import json

from django import http
from django.shortcuts import render
from django_redis import get_redis_connection
# Create your views here.
from django.views import View

from goods.models import SKU
from meiduo.utils.response_code import RETCODE


class Carts(View):
    def post(self,request):
        # 新增购物车数据
        # 1.获取数据
        body_dict = json.loads(request.body.decode())
        sku_id = body_dict.get("sku_id")
        count = body_dict.get("count")
        select = body_dict.get("selected",True)
        if not all([sku_id,count]):
            return http.HttpResponseForbidden("您缺少必须数据")
        try:
            sku = SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return http.HttpResponseForbidden("sku_id无效")
        try:
            count = int(count)
        except Exception:
            return http.HttpResponseForbidden("数据类型有误")
        if isinstance(select,bool) is False:
            return http.HttpResponseForbidden("数据类型有误")
        user = request.user
        # TODO is_authenticated 会返回True 或者False     get请求时最节省资源的一种请求
        if user.is_authenticated:
            #用户登录应该做什么
            # 需要存储什么数据呢?
            #   用户id 商品id
    #TODO 对于无需立马执行的redis命令,可以放入管道中,统一执行,可以提交效率
            redis_conn = get_redis_connection("CARTS")
            pl = redis_conn.pipeline()
            pl.hincrby('cart_%s'%user.id,sku_id,count)

            if select:
                pl.sadd('select_%s'%user.id,sku_id)
            pl.execute()

            return  http.JsonResponse({
                'code':RETCODE.OK,'errmsg':'添加购物车成功'
            })
        else:
            # 用户没有登录应该做什么
            # 需要吧数据存储到cookie之中,
            # 因为牵扯到加密,所以比较复杂
            #TODO cookie的键和值必须都时字符串,每个域名最多只能存20个cookie,前端js也能获取cookie,cookie是基于域名安全的
            cart_str =request.COOKIES.get("carts")
            if cart_str:
                cart_bytes = base64.b64decode(cart_str)
                dict_cart = json.loads(cart_bytes.decode())
                sku_id=str(sku_id)
                if sku_id in dict_cart:
                    # 获取cookie里面的数据
                    origin_count = dict_cart[sku_id]["count"]
                    count += origin_count
            else:
                dict_cart={}
            # 吧数据重新塞进字典里面.有的新增,没有的修改
            dict_cart[sku_id]={
                'count':count,
                'select':select,
            }
            data_cookie = base64.b64encode(json.dumps(dict_cart).encode())

            response = http.JsonResponse({
                'code':RETCODE.OK,
                'errmsg':"添加购物车成功",
            })
            response.set_cookie('carts',data_cookie)
            return response
    def get(self,request):
        user = request.user
        if user.is_authenticated:
            # 用户登录
            # 如果是登录用户 我需要从redis中去获取数据
            conn = get_redis_connection('CARTS')
            redis_carts = conn.hgetall('cart_%s'%user.id)
            select_redis = conn.smembers('select_%s'%user.id)
            cart_dict={}
            for i in redis_carts:
                cart_dict[int(i)]={
                    'count':int(redis_carts[i]),
                    'select':i in select_redis}
        else:
            # 用户没有登录
            cart_str = request.COOKIE.get("carts")
            if cart_str:
                #说明里面有数据
                cart_bytes = base64.b64decode(cart_str)
                cart_dict = json.loads(cart_bytes)

            else:
                return render(request,'cart.html')
        # 能走到这一步说明已经获取到数据了.
        sku_qs = SKU.objects.filter(id__in=cart_dict.keys())
        sku_list = []
        for sku_model in sku_qs:
            count = cart_dict[sku_model.id]['count']
            sku_list.append({
                'id': sku_model.id,
                'name': sku_model.name,
                'default_image_url': sku_model.default_image.url,
                'price': str(sku_model.price),  # 转成str类型是为了方便js中进行解析
                'count': count,
                'selected': str(cart_dict[sku_model.id]['select']),
                'amount': str(sku_model.price * count)
            })

        context = {
            'cart_skus': sku_list
        }
        return render(request, 'cart.html', context)


    def put(self,request):
        json_dict = json.loads(request.body.decode())
        sku_id = json_dict.get('sku_id')
        count = json_dict.get('count')
        selected = json_dict.get('selected')

        user = request.user
        if  all([sku_id,count]) is False:
              return http.HttpResponseForbidden("您请求的数据不齐全")
        try:
            sku_model = SKU.objects.get(id=sku_id)
        except:
            return http.HttpResponseForbidden("您请求的数据不齐全")

        cart_sku = {
            'id': sku_model.id,
            'name': sku_model.name,
            'default_image_url': sku_model.default_image.url,
            'price': str(sku_model.price),  # 转成str类型是为了方便js中进行解析
            'count': count,
            'selected': selected,
            'amount': str(sku_model.price * count)}
        response = http.JsonResponse({'code':RETCODE.OK,'errmsg':"OK",'cart_sku':cart_sku})
        # 判断用户是否登录
        if user.is_authenticated:
            if user.is_authenticated:
                # 登录用户修改redis
                # 创建redis连接对象
                redis_conn = get_redis_connection('CARTS')
                pl = redis_conn.pipeline()
                # 修改hash中指定key 对应 count
                pl.hset('cart_%s' % user.id, sku_id, count)
                # 判断当前商品是要勾选还是不勾选
                if selected:
                    # 勾选就将当前sku_id添加到set
                    pl.sadd('select_%s' % user.id, sku_id)

                else:
                    # 不勾选就将sku_id 从set 移除
                    pl.srem('select_%s' % user.id, sku_id)

                pl.execute()

            else:
                # 未登录用户修改cookie

                # 获取cookie购物车数据
                cart_str = request.COOKIES.get('CARTS')
                # 判断是否获取到cookie购物车数据
                if cart_str:
                    # 将cart_str 转换成字典
                    cart_bytes = base64.b64decode(cart_str)
                    cart_dict = json.loads(cart_bytes)

                else:
                    # 如果没有获取到cookie购物车数据提前响应
                    return http.JsonResponse({'code': RETCODE.NODATAERR, 'errmsg': '没有获取到数据'})
                # 覆盖cookie大字典中指定键值对
                cart_dict[sku_id] = {
                    'count': count,
                    'selected': selected
                }
                # 将字典转回字符串
                cart_str =base64.b64encode(json.dumps(cart_dict).encode())
                # # 创建响应对象
                # response = http.JsonResponse({'code': RETCODE.OK, 'errmsg': '修改购物车成功'})
                # 设置cookie
                response.set_cookie('carts', cart_str)
                # 响应
            return response
    def delete(self, request):
        """购物车删除"""
        # 1.接收请求体中非表单
        json_dict = json.loads(request.body.decode())
        sku_id = json_dict.get('sku_id')
        # 2.校验
        try:
            sku = SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return http.HttpResponseForbidden('sku_id无效')

        # 获取user
        user = request.user
        # 判断登录
        if user.is_authenticated:
            # 登录操作redis
            # 创建redis连接对象
            redis_conn = get_redis_connection('CARTS')
            # 创建管道
            pl = redis_conn.pipeline()
            # 删除hash数据
            pl.hdel('cart_%s' % user.id, sku_id)
            # 删除set
            pl.srem('select_%s' % user.id, sku_id)
            # 执行管道
            pl.execute()
            return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '删除购物车数据成功'})
        else:
            # 未登录用户cookie
            # 获取cookie购物车数据
            cart_str = request.COOKIES.get('carts')
            # 判断是否获取到cookie
            if cart_str:
                # cart_str 转 cart_dict
                cart_bytes = base64.b64decode(cart_str)
                cart_dict = json.loads(cart_bytes)
            else:
                # 提前响应
                return http.JsonResponse({'code': RETCODE.NODATAERR, 'errmsg': '没有获取到数据'})

            # 判断当前要删除的sku_id在cookie大字典中是否存在
            if sku_id in cart_dict:
                # del 删他字典中指定的键值对
                del cart_dict[sku_id]

            response = http.JsonResponse({'code': RETCODE.OK, 'errmsg': '删除购物车数据成功'})
            # 判断cookie购物车字典中否已经空了
            if not cart_dict:
                # 如果cookie购物车数据已经删除干净了,直接将浏览器上的cookie购物车数据删除
                response.delete_cookie('carts')
                return response

            # 将cart_dict  转 cart_str {}
            cart_str = base64.b64encode(json.dumps(cart_dict).encode())

            # 设置cookie
            response.set_cookie('carts', cart_str)
            # 响应
            return response

class SimpleCarts(View):
    def get(self,request):
        user = request.user
        if user.is_authenticated:
            # 用户登录
            # 如果是登录用户 我需要从redis中去获取数据
            conn = get_redis_connection('CARTS')
            redis_carts = conn.hgetall('cart_%s' % user.id)
            select_redis = conn.smembers('select_%s' % user.id)
            cart_dict = {}
            for i in redis_carts:
                cart_dict[int(i)] = {
                    'count': int(redis_carts[i]),
                    'select': i in select_redis}
        else:
            # 用户没有登录
            cart_str = request.COOKIES.get("carts")
            if cart_str:
                # 说明里面有数据
                cart_bytes = base64.b64decode(cart_str)
                cart_dict = json.loads(cart_bytes)

            else:
                return render(request, 'cart.html')
        # 能走到这一步说明已经获取到数据了.
        sku_qs = SKU.objects.filter(id__in=cart_dict.keys())
        sku_list = []
        for sku_model in sku_qs:
            # print(sku_model)
            # print()
            # print(cart_dict)
            count = cart_dict[str(sku_model.id)]['count']
            sku_list.append({
                'id': sku_model.id,
                'name': sku_model.name,
                'default_image_url': sku_model.default_image.url,
                'count': count,
            })

        return http.JsonResponse({'code':RETCODE.OK,'errmsg':"ok",'cart_skus': sku_list})
